/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.community.component.spreadsheet.analyze;

import cn.ac.nercis.pes.common.constant.common.BaseConstants;
import cn.ac.nercis.pes.common.constant.evaluation.RiskLevel;
import cn.ac.nercis.pes.community.component.spreadsheet.TableSheetView;
import cn.ac.nercis.pes.community.model.vo.evaluation.UnitRiskAnalysisVO;
import cn.ac.nercis.pes.community.support.event.EventCallback;
import cn.ac.nercis.pes.community.utils.IconUtils;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Tooltip;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.controlsfx.control.spreadsheet.GridBase;
import org.controlsfx.control.spreadsheet.SpreadsheetCell;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 风险分析表控件
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
public class RiskAnalysisSheetView extends TableSheetView<UnitRiskAnalysisVO> {
    private final static Integer EMPTY_DATA_COUNT = 1;
    private final static List<String> COLUMNS = List.of("测评指标","问题描述","风险分析","风险等级","关联威胁","整改建议","操作");
    private final static Integer TARGET_COLUMN_INDEX = 0;
    private final static Integer PROBLEM_COLUMN_INDEX = 1;
    private final static Integer ANALYSIS_COLUMN_INDEX = 2;
    private final static Integer LEVEL_COLUMN_INDEX = 3;
    private final static Integer THREAT_COLUMN_INDEX = 4;
    private final static Integer SUGGEST_COLUMN_INDEX = 5;
    private final static Integer OPTION_COLUMN_INDEX = 6;

    private final ObservableList<String> riskLevelList;
    private EventCallback<UnitRiskAnalysisVO> onOptionAction;

    public RiskAnalysisSheetView(){
        this.getStyleClass().add("pes-sheet-view");
        riskLevelList = FXCollections.observableArrayList(RiskLevel.findRiskLevels().stream().map(RiskLevel::getName).toList());
        var grid = new GridBase(EMPTY_DATA_COUNT, COLUMNS.size());
        grid.setRowHeightCallback(new GridBase.MapBasedRowHeightFactory(heardRowHeight()));
        grid.getColumnHeaders().addAll(COLUMNS);
        setGrid(grid);
        getColumns().get(TARGET_COLUMN_INDEX).setPrefWidth(180);
        getColumns().get(PROBLEM_COLUMN_INDEX).setPrefWidth(250);
        getColumns().get(ANALYSIS_COLUMN_INDEX).setPrefWidth(250);
        getColumns().get(LEVEL_COLUMN_INDEX).setPrefWidth(90);
        getColumns().get(THREAT_COLUMN_INDEX).setPrefWidth(90);
        getColumns().get(SUGGEST_COLUMN_INDEX).setPrefWidth(200);
        getColumns().get(OPTION_COLUMN_INDEX).setPrefWidth(80);
    }

    public void initialize(EventCallback<UnitRiskAnalysisVO> onOptionAction){
        this.onOptionAction = onOptionAction;
        this.editModel.set(false);
    }

    public List<UnitRiskAnalysisVO> getRiskAnalysisList(){
        return this.sheetData;
    }

    public void loadContent(List<UnitRiskAnalysisVO> data){
        this.editModel.set(false);
        this.sheetData= data;
        this.clearContent();
        for(var dataIndex = 0; dataIndex< data.size(); dataIndex++){
            this.loadContent(data.get(dataIndex),toSheetRowIndex(dataIndex));
        }
        setGrid(getGrid());
        this.editModel.set(true);
    }

    public List<UnitRiskAnalysisVO> getModifyData(){
        List<UnitRiskAnalysisVO> data = new ArrayList<>();
        for(var sheetRowIndex=0;sheetRowIndex<this.getGrid().getRows().size();sheetRowIndex++){
            if(this.isEmptyData(sheetRowIndex)){
                continue;
            }
            data.add(getModifyData(sheetRowIndex));
        }
        return data.stream()
                .filter(item-> Objects.nonNull(item) && item.isChange())
                .collect(Collectors.toList());
    }

    private UnitRiskAnalysisVO getModifyData(Integer sheetRowIndex){
        if (toDataIndex(sheetRowIndex) < 0 || toDataIndex(sheetRowIndex) >= this.sheetData.size()) {
            return null;
        }
        var rowData = this.getGrid().getRows().get(sheetRowIndex);
        UnitRiskAnalysisVO info = this.sheetData.get(toDataIndex(sheetRowIndex));
        info.setProblem(StringUtils.trim(rowData.get(PROBLEM_COLUMN_INDEX).getText()));
        info.setSuggest(StringUtils.trim(rowData.get(SUGGEST_COLUMN_INDEX).getText()));
        info.setAnalysis(StringUtils.trim(rowData.get(ANALYSIS_COLUMN_INDEX).getText()));
        info.setRiskLevel(StringUtils.trim(rowData.get(LEVEL_COLUMN_INDEX).getText()));
        return info;
    }

    @Override
    public ContextMenu getSpreadsheetViewContextMenu() {
        return generateContextMenu(false);
    }

    protected Map<Integer,Double> heardRowHeight(){
        Map<Integer, Double> rowHeight = new HashMap<>(100);
        IntStream.range(0,20).forEach(number->rowHeight.put(number,100.0));
        return rowHeight;
    }

    @Override
    protected void loadContent(UnitRiskAnalysisVO info,Integer sheetRowIndex){
        final ObservableList<SpreadsheetCell> data = FXCollections.observableArrayList();

        data.add(getTextAreaCell(sheetRowIndex,TARGET_COLUMN_INDEX,info.getUnitTargetName(),false));
        data.add(getTextAreaCell(sheetRowIndex,PROBLEM_COLUMN_INDEX,processNewline(info.getProblem()),true,"data-cell-left"));
        data.add(getTextAreaCell(sheetRowIndex,ANALYSIS_COLUMN_INDEX,processNewline(info.getAnalysis()),true,"data-cell-left"));
        data.add(getComboBoxCell(sheetRowIndex,LEVEL_COLUMN_INDEX, riskLevelList,info.getRiskLevel()));
        data.add(getTextAreaCell(sheetRowIndex,THREAT_COLUMN_INDEX,getRenderThreatCode(info.getThreatCode()),false));
        data.add(getTextAreaCell(sheetRowIndex,SUGGEST_COLUMN_INDEX,processNewline(info.getSuggest()),true,"data-cell-left"));
        var optionCell = getOptionCell(sheetRowIndex,OPTION_COLUMN_INDEX);
        Button option = new Button();
        option.getStyleClass().add("sheet-view-option-button");
        option.setGraphic(IconUtils.getGlyph("report-step-icon","sheet-view-option-icon"));
        option.setTooltip(new Tooltip("风险分析"));
        option.setOnAction((event)->{
            if(Objects.nonNull(this.onOptionAction)){
                this.onOptionAction.action(info);
            }
        });
        optionCell.setGraphic(option);
        data.add(optionCell);

        this.getGrid().getRows().add(data);
    }

    private String getRenderThreatCode(String threatCode){
        if(StringUtils.isBlank(threatCode)){
            return threatCode;
        }
        return String.join(BaseConstants.NEW_LINE, StringUtils.split(threatCode, BaseConstants.MULTI_SPLIT_CHAR));
    }

    @Override
    protected void clearContent(){
        int endIndex = this.getGrid().getRows().size() -1;
        for(;endIndex>=0;endIndex--){
            this.getGrid().getRows().remove(endIndex);
        }
    }

    @Override
    protected boolean isEmptyData(Integer sheetRowIndex) {
        return toDataIndex(sheetRowIndex) < 0;
    }

    @Override
    protected boolean validate(ObservableList<SpreadsheetCell> rowData) {
        return true;
    }

    @Override
    protected void clearValidate(ObservableList<SpreadsheetCell> rowData) {
    }

    @Override
    protected List<String> getDataColumns() {
        return COLUMNS;
    }

    @Override
    protected ObservableList<SpreadsheetCell> generateEmptyDataRow(int rowIndex) {
        return null;
    }

    @Override
    protected void deleteData() {
    }


}